#include <engine/e_server_interface.h>
#include <engine/e_config.h>
#include <game/mapitems.hpp>
#include <game/server/entities/character.hpp>
#include <game/server/player.hpp>
#include <game/server/gamecontext.hpp>
#include <string.h>
#include "zombie.hpp"

GAMECONTROLLER_ZOMBIE::GAMECONTROLLER_ZOMBIE()
{
	if (config.dmod_gametype_custom == 0)
	gametype = "ZM";
	else
	gametype = config.dmod_gametype_custom_name;
	game_flags = GAMEFLAG_TEAMS;
	last_zombie = -1;
}

const char *GAMECONTROLLER_ZOMBIE::get_team_name(int team)
{
	if(team == 0)
		return "zombies";
	else if(team == 1)
		return "brains";
	return "spectators";
}



int GAMECONTROLLER_ZOMBIE::on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon)
{
	if(!killer)
		return 0;
	if(killer == victim->player && config.dmod_player_suicide_score == 1)
	{
		victim->player->score--; // suicide
		if(killer->team == 1)
		{
			killer->team = 0;
		}
		return 0;
	}
	else
	{
		if(victim->team == killer->team && config.dmod_team_kill_score == 1)
		{
			killer->score--; // teamkill
			return 0;
		}
	}
	if(victim->team==0)killer->score+=1;
	if((victim->team==1)&&(killer->team==0))
	{
		killer->score++;
		victim->team=victim->player->team=0;
		victim->increase_health(10);
		victim->increase_armor(10);
		
		victim->active_weapon=0;
		victim->weapons[WEAPON_HAMMER].got = 1;
		victim->weapons[WEAPON_HAMMER].ammo = -1;
		victim->weapons[WEAPON_GUN].got = 0;
		victim->weapons[WEAPON_GRENADE].got = 0;
		victim->weapons[WEAPON_SHOTGUN].got = 0;
		victim->weapons[WEAPON_RIFLE].got = 0;
		victim->weapons[WEAPON_GUN].ammo = 0;
		victim->weapons[WEAPON_GRENADE].ammo = 0;
		victim->weapons[WEAPON_SHOTGUN].ammo = 0;
		victim->weapons[WEAPON_RIFLE].ammo = 0;
		return -1;
		
	}
	return 0;
}

void GAMECONTROLLER_ZOMBIE::startround()
{
	GAMECONTROLLER::startround();
	int players=0;
	for(int t=0;t<MAX_CLIENTS;t++)
	{
		if((game.players[t])&&(game.players[t]->team!=-1))
		{
			game.players[t]->team = 1;
			game.players[t]->get_character()->team = 1;
			players++;
		}
	}
	tl = (int)( (log( (double)(players+1)*(players+1) ) / 6.0f + 0.1f) * config.sv_timelimit);
	if(tl==0)tl=1;
	//dbg_msg("!!!","%i,%f",tl,((double)log(players*players+1)/6+0.1)*config.sv_timelimit);
}

void GAMECONTROLLER_ZOMBIE::on_character_spawn(class CHARACTER *chr)
{
	GAMECONTROLLER::on_character_spawn(chr);
	
	if(chr->team==0)
	{
		chr->increase_health(10);
		chr->increase_armor(10);
		chr->active_weapon=0;
		chr->weapons[WEAPON_HAMMER].got = 1;
		chr->weapons[WEAPON_HAMMER].ammo = -1;
		chr->weapons[WEAPON_GUN].got = 0;
		chr->weapons[WEAPON_GRENADE].got = 0;
		chr->weapons[WEAPON_SHOTGUN].got = 0;
		chr->weapons[WEAPON_RIFLE].got = 0;
		chr->weapons[WEAPON_GUN].ammo = 0;
		chr->weapons[WEAPON_GRENADE].ammo = 0;
		chr->weapons[WEAPON_SHOTGUN].ammo = 0;
		chr->weapons[WEAPON_RIFLE].ammo = 0;
	}
}

void GAMECONTROLLER_ZOMBIE::do_team_score_wincheck()
{
	if(game_over_tick == -1 && !warmup)
	{
		// check score win condition
		if((config.sv_timelimit > 0 && (server_tick()-round_start_tick) > tl*60*server_tickspeed()))
		{
			teamscore[1] = 1;
			teamscore[0] = 0;
			endround();
		}
		int numplayers=0;
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			if(game.players[i] && game.players[i]->team==1)
				numplayers++;
		}
		//dbg_msg("srv", "ololo %i", numplayers);
		if(numplayers==0)
		{
			teamscore[0] = 1;
			teamscore[1] = 0;
			endround();
		}
	}
}

void GAMECONTROLLER_ZOMBIE::snap(int snapping_client)
{
	NETOBJ_GAME *gameobj = (NETOBJ_GAME *)snap_new_item(NETOBJTYPE_GAME, 0, sizeof(NETOBJ_GAME));
	gameobj->paused = game.world.paused;
	gameobj->game_over = game_over_tick==-1?0:1;
	gameobj->sudden_death = sudden_death;
	
	gameobj->score_limit = config.sv_scorelimit;
	gameobj->time_limit = tl;
	gameobj->round_start_tick = round_start_tick;
	gameobj->flags = game_flags;
	
	gameobj->warmup = warmup;
	
	gameobj->round_num = (strlen(config.sv_maprotation) && config.sv_rounds_per_map) ? config.sv_rounds_per_map : 0;
	gameobj->round_current = round_count+1;
	
	
	if(snapping_client == -1)
	{
		// we are recording a demo, just set the scores
		gameobj->teamscore_red = teamscore[0];
		gameobj->teamscore_blue = teamscore[1];
	}
	else
	{
		// TODO: this little hack should be removed
		gameobj->teamscore_red = is_teamplay() ? teamscore[0] : game.players[snapping_client]->score;
		gameobj->teamscore_blue = teamscore[1];
	}
}

void GAMECONTROLLER_ZOMBIE::tick()
{
	do_team_score_wincheck();
	if(game_over_tick != -1)
	{
		// game over.. wait for restart
		if(server_tick() > game_over_tick+server_tickspeed()*10)
		{
			cyclemap();
			startround();
			round_count++;
		}
	}

	int numplayers=0;
	int numzombies=0;
	for(int i = 0; i < MAX_CLIENTS; i++)
	{
		if(game.players[i] && game.players[i]->team==1)
			numplayers++;
		if(game.players[i] && game.players[i]->team==0)
			numzombies++;
	}
	if((numzombies==0)&&(numplayers!=0))
	{
		int t = last_zombie;
		t++;
		while(t!=last_zombie)
		{
			if((game.players[t])&&(game.players[t]->team!=-1))
				break;
			t++;
			if(t>=MAX_CLIENTS)t=0;
		}
		if((t!=last_zombie)&&(t!=-1))
		{
			game.players[t]->team = 0;
			game.players[t]->get_character()->team = 0;
			game.players[t]->get_character()->active_weapon=0;
			game.players[t]->get_character()->weapons[WEAPON_HAMMER].got = 1;
			game.players[t]->get_character()->weapons[WEAPON_HAMMER].ammo = -1;
			game.players[t]->get_character()->weapons[WEAPON_GUN].got = 0;
			game.players[t]->get_character()->weapons[WEAPON_GRENADE].got = 0;
			game.players[t]->get_character()->weapons[WEAPON_SHOTGUN].got = 0;
			game.players[t]->get_character()->weapons[WEAPON_RIFLE].got = 0;
			game.players[t]->get_character()->weapons[WEAPON_GUN].ammo = 0;
			game.players[t]->get_character()->weapons[WEAPON_GRENADE].ammo = 0;
			game.players[t]->get_character()->weapons[WEAPON_SHOTGUN].ammo = 0;
			game.players[t]->get_character()->weapons[WEAPON_RIFLE].ammo = 0;
			last_zombie = t;
		}
	}

}

int GAMECONTROLLER_ZOMBIE::do_pickup(class CHARACTER *chr , int type , int subtype)
{
	if(chr->team==0)return 0;
	return 1;
}

bool GAMECONTROLLER_ZOMBIE::can_join_team(int team, int notthisid)
{
	if(team==-1)
		return true;
	if(game.players[notthisid]->team==-1)
		return true;
	return false;
}

bool GAMECONTROLLER_ZOMBIE::check_team_balance()
{
	unbalanced_tick = -1;
	return true;
}

int GAMECONTROLLER_ZOMBIE::get_auto_team(int notthisid)
{
	
	int numplayers=0;
	for(int i = 0; i < MAX_CLIENTS; i++)
	{
		if(game.players[i] && game.players[i]->team==0)
			numplayers++;
	}
	if(numplayers==1)
	{
		last_zombie=notthisid;
		return 0;
	}
	else
		return 1;
}

